<?php

class Erra_Core_HtmlStream {

    public static $firebugLiteStack = '';
    public static $css = array();
    public static $js = array();
    public static $js_framework = array();
    public static $jsnomerge = array();
    public static $jsvar = array();
    public static $jsl10n = array();
    public static $css_framework = array();
    public static $cssnomerge = array();
    public static $rss = array();
    public static $meta = array();
    public static $title = '';
    public static $doctype = 'HTML 5';
    public static $preview = false;

    /**
     * Javascript escape
     *
     * Returns a protected JavaScript string
     *
     * @param string $str String to protect
     * @return string
     */
    public static function escapeJS($str) {
        $str = htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8');
        $str = str_replace("'", "\'", $str);
        $str = str_replace('"', '\"', $str);
        return $str;
    }

    /**
     * self::loadUnmergedJs() - Loads unmerged js
     *
     * @param array $css
     * @return
     */
    public static function loadHtml5Js() {
        $res = '';
        $res .= '<script src="' . config_get('framework_js') . '/html5.js" type="text/javascript" ' . END_UNI_MKP . '></script>' . "\n";
        return $res;
    }

    /**
     * self::loadUnmergedJs() - Loads unmerged js
     *

     * @param array $css

     * @return

     */
    public static function loadUnmergedJs() {

        $res = '';

        if (isset(self::$jsnomerge) && count(self::$jsnomerge)) {

            self::$jsnomerge = array_unique(self::$jsnomerge);

            foreach (self::$jsnomerge as $j) {

                $res .= '<script src="' . $j . '" type="text/javascript" ' . END_UNI_MKP . '></script>' . "\n";
            }
        }

        return $res;
    }

    /**

     * self::loadJs() - Load javascript from array and html code

     *

     * @param array $liste

     * @param array $vars

     * @param integer $compatible

     * @return

     */
    public static function loadJs($liste = array(), $folder = null, $suffix = null, $vars = array()) {

        $res = '';

        if (count($liste)) {

            if (count($vars)) {
                $res .= '<script type="text/javascript">' . "\n";
                $res .= '//<![CDATA[' . "\n";
                foreach ($vars as $k => $v) {
                    $res .= $k . ' = \'' . self::escapeJS($v) . '\';';
                }
                $res .= "\n" . '//]]>' . "\n";

                // Add l10n vars if exists
                if (count(self::$jsl10n)) {
                    $res .= '//<![CDATA[' . "\n";
                    foreach (self::$jsl10n as $k => $v) {
                        $res .= $k . ' = \'' . self::escapeJS($v) . '\';' . "\n";
                    }
                    $res .= '//]]>' . "\n";
                }
                $res .= '</script>' . "\n";
            }

            $liste = array_unique($liste);

            if (config_get("optimization.minimize_js") == 1) {

                $url = self::minifyAndMergeJS($liste, $folder, $suffix);

                $res .= '<script type="text/javascript" src="' . $url . '"></script>' . "\n";
            } else {

                foreach ($liste as $jsf) {

                    $res .= '<script type="text/javascript" src="' . $jsf . '"></script>' . "\n";
                }
            }
        }

        return $res;
    }

    /**

     * self::minifyAndMergeJS() - Merge Javascript files

     *

     * @param mixed $liste

     * @return

     */
    public static function minifyAndMergeJS($liste, $folder = null, $suffix = null) {

        $sep = '!';

        $liste = array_unique($liste);

        $control = substr(md5(implode($sep, $liste)), 2, 6);

        $js_dir = DOCUMENT_ROOT . '/' . config_get("path.public_directory") . $folder . '/js/merged';

        $file = DOCUMENT_ROOT . '/' . config_get("path.public_directory") . $folder . '/js/merged/merged-' . $suffix . $control . '.js';

        $url = config_get("application.http_webroot") . $folder . '/js/merged/merged-' . $suffix . $control . '.js';



        $mtime = !file_exists($file) ? 0 : filemtime($file);



        $reload = false;

        foreach ($liste as $js) {

            if (filemtime(Erra_Core_File::web2path($js)) > $mtime) {

                $reload = true;

                break;
            }
        }

        if (!$reload) {

            return $url;
        }



        $js = '';

        foreach ($liste as $l) {

            $fileName = Erra_Core_File::web2path($l);

            if (!empty($fileName)) {

                $js .= file_get_contents($fileName) . "\n\n";
            }
        }

        $fp = fopen($file, 'wb');

        fwrite($fp, $js);

        fclose($fp);



        return $url;
    }

    /**

     * self::callJs() - Call javascript file by adding code

     *

     * @param mixed $js

     * @return

     */
    public static function callJs($js) {

        if (trim($js) == '') {

            return '';
        }

        $res = '<script type="text/javascript">' . "\n";

        $res .= '//<![CDATA[' . "\n";

        $res .= $js;

        $res .= "\n" . '//]]>' . "\n";

        $res .= '</script>' . "\n";

        return $res;
    }

    /**

     * self::loadUnmergedCss() - Loads unmerged css

     *

     * @param array $css

     * @return

     */
    public static function loadUnmergedCss() {

        $res = '';

        if (isset(self::$cssnomerge) && count(self::$cssnomerge)) {

            self::$cssnomerge = array_unique(self::$cssnomerge);

            foreach (self::$cssnomerge as $c) {

                $res .= '<link href="' . $c . '" rel="stylesheet" type="text/css" ' . END_UNI_MKP . '>' . "\n";
            }
        }

        return $res;
    }

    /**

     * self::loadCss() - Reads css from array and html file

     *

     * @param array $css

     * @return

     */
    public static function loadCss($css = array(), $folder = null, $suffix = null) {

        $res = '';

        if (count($css) > 0) {

            foreach ($css as $condition => $href) {

                if ($condition === 'IE') {

                    $res .= '<!--[if IE]>' . "\n\t" . '<link href="' . $href . '" rel="stylesheet" type="text/css" ' . END_UNI_MKP . '>' . "\n" . '<![endif]-->' . "\n";
                }
            }

            $cssmerged = self::minifyAndMergeCSS($css, $folder, $suffix);

            if ($cssmerged !== false && config_get("optimization.minimize_css")) {

                $res .= '<link href="' . $cssmerged . '" rel="stylesheet" type="text/css" ' . END_UNI_MKP . '>' . "\n";
            } else {

                $css = array_unique($css);

                foreach ($css as $c) {

                    $res .= '<link href="' . $c . '" rel="stylesheet" type="text/css" ' . END_UNI_MKP . '>' . "\n";
                }
            }
        }

        return $res;
    }

    /**

     * self::minifyAndMergeCSS() - Merge CSS files

     *

     * @param mixed $liste

     * @return

     */
    public static function minifyAndMergeCSS($liste, $folder = null, $suffix = null) {

        $liste = array_unique($liste);

        $control = substr(md5(implode('!', $liste)), 2, 6);



        $file = DOCUMENT_ROOT . '/' . config_get("path.public_directory") . $folder . '/style/merged/merged-' . $suffix . $control . '.css.php';

        $url = config_get("application.http_webroot") . $folder . '/style/merged/merged-' . $suffix . $control . '.css.php';

        $mtime = !file_exists($file) ? 0 : filemtime($file);



        $reload = false;

        foreach ($liste as $condition => $css) {

            if ($condition === 'IE') {

                continue;
            }

            if (strstr(Erra_Core_File::web2path($css), 'http') === FALSE && filemtime(Erra_Core_File::web2path($css)) > $mtime) {

                $reload = true;

                break;
            }
        }

        if (!$reload) {

            return $url;
        }



        $css = '';

        foreach ($liste as $condition => $l) {

            if ($condition === 'IE') {

                continue;
            }

            $f = Erra_Core_File::web2path($l);

            if (file_exists($f)) {

                $css .= file_get_contents($f) . "\n\n";
            }
        }



        $css = self::minifyCss($css);



        $phpCSS = '<?php

                           //ob_start ("ob_gzhandler");

                           header ("content-type: text/css; charset: UTF-8");

                           header ("cache-control: must-revalidate");

                           $offset = 60 * 60;

                           $expire = "expires: " . gmdate ("D, d M Y H:i:s", time() + $offset) . " GMT";

                           header ($expire);

                       ?>' . "\n" . $css;



        if (file_put_contents($file, $phpCSS)) {



            return $url;
        } else {

            return false;
        }
    }

    /**

     * self::minifyCss() - Minify CSS

     *

     * @param mixed $css

     * @return

     */
    public static function minifyCss($css) {

        // Remove line breaks

        $css = str_replace("\n", '', $css);

        $css = str_replace("\r", '', $css);

        // Remove comments

        $css = preg_replace('|\/\*.*\*\/|U', '', $css);

        // Remove spaces between characters

        $chars = array(':', '{', '}', ';', ',');

        foreach ($chars as $c) {

            $css = preg_replace('|\s*' . $c . '\s*|', $c, $css);
        }

        // Remove double spaces

        $css = preg_replace('|\s+|', ' ', $css);

        return $css;
    }

    /**

     * self::buildPage() - Construct HTML page with all parameters

     *

     * @param mixed $res

     * @param array $js

     * @param array $jsvar

     * @param array $css

     * @param array $rss

     * @param mixed $return_content

     * @param array $meta

     * @param array $search

     * @param string $standard

     * @return

     */
    public static function buildPage($res) {
        if (preg_match('|<raw>(.*?)</raw>|ms', $res, $mt)) {
            echo trim(str_replace(array('<raw>', '</raw>', '<ajax>', '</ajax>'), '', $mt[1]));
            exit();
        }
        $p_title = self::$title;

        $p_description = '';

        $p_keywords = '';

        $p_head = '';

        $p_content = '';

        $p_attributes = '';



        if (preg_match('|<head>(.*?)</head|ms', $res, $m)) {

            if (preg_match('|<title>(.*?)</title>|ms', $m[1], $mt)) {

                $p_title = $mt[1];
            }

            if (preg_match('|<description>(.*?)</description>|ms', $m[1], $mt)) {

                $p_description = $mt[1];
            }

            if (preg_match('|<keywords>(.*?)</keywords>|ms', $m[1], $mt)) {

                $p_keywords = $mt[1];
            }



            if (preg_match_all('|(<style.*?>.*?</style>)|ms', $m[1], $ms)) {

                foreach ($ms[1] as $v) {

                    $p_head .= $v . "\n";
                }
            }
        }



        if (preg_match('|<body(.*?)>(.*?)</body>|ms', $res, $m)) {

            $p_content = $m[2];

            $p_attributes = $m[1];
        } else {

            $p_content = str_replace($p_head, '', $res);
        }





        if (isset($GLOBALS['title'])) {

            if (is_string($GLOBALS['title'])) {

                $GLOBALS['title'] = array($GLOBALS['title']);
            }
        } else {

            $GLOBALS['title'] = array();
        }



        $p_title = array($p_title);

        $p_title = array_merge($p_title, $GLOBALS['title']);

        $p_title = trim(implode(' - ', $p_title), ' -');



        $content = '';

        $content = self::head($p_title, $p_description, $p_keywords, $p_head, $p_attributes);

        // Remplace if we are in preview mode

        if (self::$preview == true && preg_match('|<preview>(.*?)</preview>|ms', $p_content, $matches)) {

            $p_content = $matches[1];
        }



        $content .= $p_content;

        if (config_get('defer_javascript')) {
            $content .= self::loadJs(self::$js_framework, '/__erra', 'erra-', self::$jsvar);
            $content .= self::loadJs(self::$js);
            $content .= self::loadUnmergedJs();
            $content .= self::loadJs(array(config_get('framework_js') . '/framework_boot.js'));
        }


        $content .= self::foot();

        /* HYPER CACHE */
        /* if (config_get('production_mode') == 0) {
          $cache_file = Erra_Utils_Tools::toUrlCompliant(str_replace(array('/', '-'), ' ', $_SERVER['REDIRECT_QUERY_STRING'])) . '.cache';
          $compile_path = Erra_Core_Lexer::getCleanPath(DOCUMENT_ROOT . '/' . config_get("path.public_directory") . '/__cache/static_pages/' . $cache_file);
          file_put_contents($compile_path, $content);
          } */
        return $content;
    }

    /**

     * self::head() - Builds HEAD structure

     *

     * @param string $title

     * @param string $description

     * @param string $keywords

     * @param string $head

     * @param array $js

     * @param array $jsvar

     * @param array $css

     * @param array $rss

     * @param integer $compatible

     * @param array $meta

     * @param array $search

     * @param string $standard

     * @param string $body_attributes

     * @return

     */
    public static function head($title = '', $description = '', $keywords = '', $head = '', $body_attributes = '') {

        if (defined('LANG')) {

            $lang = LANG;
        } else {

            $lang = Erra_Core_Locale::getDefaultLang();
        }



        $res = '';



        $firebug_lite_active = (config_get("debug.firebug_lite")) ? 'debug="true"' : '';

        if (self::$doctype == 'XHTML 1.0 Strict') {

            $res .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n";

            $res .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $lang . '" lang="' . $lang . '" ' . $firebug_lite_active . '>' . "\n";

            if (!defined('END_UNI_MKP')) {

                define('END_UNI_MKP', '/');
            }
        } elseif (self::$doctype == 'XHTML 1.0 Transitional') {

            $res .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";

            $res .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $lang . '" lang="' . $lang . '" ' . $firebug_lite_active . '>' . "\n";

            if (!defined('END_UNI_MKP')) {

                @define('END_UNI_MKP', '/');
            }
        } elseif (self::$doctype == 'HTML 4.01') {

            $res .= '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">' . "\n";

            $res .= '<html lang="' . $lang . '" ' . $firebug_lite_active . '>' . "\n";

            if (!defined('END_UNI_MKP')) {

                @define('END_UNI_MKP', '');
            }
        } elseif (self::$doctype == 'XHTML 1.1') {

            $res .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">' . "\n";

            $res .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $lang . '" ' . $firebug_lite_active . '>' . "\n";

            if (!defined('END_UNI_MKP')) {

                @define('END_UNI_MKP', '/');
            }
        } else if (self::$doctype == 'HTML 5') {

            $res .= '<!DOCTYPE html>' . "\n";

            $res .= '<html lang="' . $lang . '" ' . $firebug_lite_active . '>' . "\n";

            if (!defined('END_UNI_MKP')) {

                @define('END_UNI_MKP', '');
            }
        } else {

            $res .= '<html>';

            if (!defined('END_UNI_MKP')) {

                @define('END_UNI_MKP', '');
            }
        }

        $res .= '<head>' . "\n";
        $res .= '<title>' . $title . '</title>' . "\n";
        $res .= '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" ' . END_UNI_MKP . '>' . "\n";

        $res .= self::meta();
        if (file_exists(PUBLIC_ROOT . '/images/favicon.png')) {
            $res .= self::favicon(config_get("application.http_webroot") . '/images/favicon.png');
        }


        // Load CSS in HTML

        $res .= self::loadCss(self::$css_framework, '/__erra', 'erra-');

        $res .= self::loadCss(self::$css);

        $res .= self::loadUnmergedCss();

        // Load HTML5 JS if LTE IE9
        if (\Erra\Core\Browser::getSingleton()->getBrowser() == \Erra\Core\Browser::BROWSER_IE && \Erra\Core\Browser::getSingleton()->getVersion() <= 8) {
            $res .= self::loadHtml5Js();
        }

        // Load HTML5JS 

        if (!config_get('defer_javascript')) {
            $res .= self::loadJs(self::$js_framework, '/__erra', 'erra-', self::$jsvar);
            $res .= self::loadJs(self::$js);
            $res .= self::loadUnmergedJs();
            $res .= self::loadJs(array(config_get('framework_js') . '/framework_boot.js'));
        }




        foreach (self::$rss as $title => $fil) {
            $res .= '<link rel="alternate" type="application/rss+xml" title="' . $title . '" href="' . $fil . '" ' . END_UNI_MKP . '>' . "\n";
        }



        $res .= $head . "\n";

        $res .= self::googleAnalytics(config_get('application.google_analytics'));
        $res .= '</head>' . "\n";

        if ($body_attributes != '') {

            $res .= '<body ' . trim($body_attributes) . '>' . "\n";
        } else {

            $res .= '<body>' . "\n";
        }

        return $res;
    }

    /**

     * self::favicon() - Loads favicon

     *

     * @param mixed $ico

     * @return

     */
    public static function favicon($ico) {
        $res = '';
        $res .= '<link href="' . $ico . '" rel="icon" type="image/png" />' . "\n";
        return $res;
    }

    /**

     * HTML escape

     *

     * Replaces HTML special characters by entities.

     *

     * @param string $str String to escape

     * @return string

     */
    public static function escapeHTML($str) {

        return htmlspecialchars($str, ENT_COMPAT, 'UTF-8');
    }

    /**

     * self::meta() - Write meta tags

     *

     * @param mixed $meta

     * @return

     */
    public static function meta() {

        $res = '';

        foreach (self::$meta as $name => $content) {

            if (trim($content) == '') {

                continue;
            }

            $aname = 'name';

            if (substr($name, 0, 3) == 'og:') {

                $aname = 'property';
            }

            $res .= '<meta ' . $aname . '="' . self::escapeHTML($name) . '" content="' . trim(self::removeNL(self::escapeHTML($content))) . '" ' . END_UNI_MKP . '>' . "\n";
        }

        return $res;
    }

    /**

     * self::foot() - Writes footer

     *

     * @return

     */
    public static function foot() {

        $footer = '';

        // Writes firebug statements

        if (config_get("debug.firebug_lite")) {

            $footer .= self::$firebugLiteStack . "\n";
        }



        // Enable CSS3 pie for ie <= 8

        if (\Erra\Core\Browser::getSingleton()->getBrowser() == \Erra\Core\Browser::BROWSER_IE && \Erra\Core\Browser::getSingleton()->getVersion() <= 8) {

            $footer .= '<script type="text/javascript">

                    $(function() {

                        if (window.PIE) {

                            $(".css3legacy").each(function() {

                                PIE.attach(this);

                            });

                        }

                    });

        </script>';
        }

        $footer .= '</body>' . "\n" . '</html>';

        return $footer;
    }

    /**

     * self::removeNl() - Removes newlines

     *

     * @param mixed $str

     * @return

     */
    public static function removeNl($str) {

        $trans = array("\n" => ' ', "\r" => ' ');

        $str = strtr($str, $trans);

        return self::condenseWhite($str);
    }

    /**

     * self::condenseWhite() - Codense white spaces

     *

     * @param mixed $str

     * @return

     */
    public static function condenseWhite($str) {

        return preg_replace('|[\s]{2,100}|u', ' ', $str);
    }

    /**

     * self::multiExplode() - Multidimensional explode function

     *

     * @param mixed $separator

     * @param mixed $str

     * @param mixed $limit

     * @return

     */
    public static function multiExplode($separator, $str, $limit = null) {

        $seps = array('Â§', 'Â£', 'Â¤', '#', 'Â¨', '^', '%');

        foreach ($seps as $sep) {

            if (stristr($str, $sep)) {

                continue;
            }

            break;
        }





        $str = preg_replace('|[' . preg_quote($separator, '-') . ']|', $sep, $str);

        if (is_null($limit)) {

            return explode($sep, $str);
        } else {

            return explode($sep, $str, $limit);
        }
    }

    /**

     * self::getArgs() - Returns url arguments

     *

     * @param mixed $args

     * @return

     */
    public static function getArgs($args = null) {

        if (is_null($args)) {

            $args = $_SERVER['PATH_INFO'];
        }

        $args = str_replace(config_get("application.http_webroot"), '', '/' . $args);





        $args = explode('/', trim($args, '/'));

        if (count($args) == 1 && ($args[0] == '' || is_null($args[0]))) {

            return array();
        }



        foreach ($args as $k => $v) {

            if (preg_match('|%[A-F0-9a-f]{2}|', $v)) {

                $args[$k] = urldecode($v);
            }
        }



        return $args;
    }

    /**

     * self::googleAnalytics() - Displays code for google analytics

     *

     * @param mixed $code

     * @param mixed $track

     * @return

     */
    public static function googleAnalytics($code = null) {
        $res = '';
        if (is_string($code) && strstr($code, 'UA')) {
            $res = "\n" . "<script type=\"text/javascript\">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', '" . $code . "']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>" . "\n";
        }

        return $res;
    }

}

?>